分类
联系方式
  1. 新浪微博
  2. E-mail

Dart eval:Compiler populateLookupTablesForDeclaration

介绍

解析 Library 中的所有声明,并更新到 Context 注册表中。

方法签名:

void _populateLookupTablesForDeclaration(
  int libraryIndex,
  DeclarationOrBridge declarationOrBridge) {

入参:

  1. 库的索引
  2. 对应的声明,具体指 Top level declaration

初始化工作:

void _populateLookupTablesForDeclaration(
    int libraryIndex, DeclarationOrBridge declarationOrBridge) {
  // 如果没有初始化,则初始化
  if (!_topLevelDeclarationsMap.containsKey(libraryIndex)) {
    _topLevelDeclarationsMap[libraryIndex] = {};
  }
  // 如果没有初始化,则初始化
  if (!_instanceDeclarationsMap.containsKey(libraryIndex)) {
    _instanceDeclarationsMap[libraryIndex] = {};
  }
  // ……

根据 declarationOrBridge 的类型,解析分为几种类型:

  1. 是不是 Bridge:桥接类
  2. 是不是 TopLevelVariableDeclaration:顶层变量声明
  3. NamedCompilationUnitMember:顶层其它声明,如类声明

Bridge 处理逻辑

如果是 Bridge:

// 如果是 Bridge
if (declarationOrBridge.isBridge) {
  // 获取到这个 Bridge 
  final bridge = declarationOrBridge.bridge!;
  // 还区分 Bridge 桥接的类型
  // 1. 桥接类
  // 2. 桥接枚举
  // 3. 桥接方法
  
  // 如果是类桥接
  if (bridge is BridgeClassDef) {
    final spec = bridge.type.type.spec!;
    
    // 类本身放进去
    _topLevelDeclarationsMap[libraryIndex]![spec.name] =
        DeclarationOrBridge(libraryIndex, bridge: bridge);
    
    // 一个类可能有多个构造方法,放进去
    for (final constructor in bridge.constructors.entries) {
      _topLevelDeclarationsMap[libraryIndex]![
              '${spec.name}.${constructor.key}'] =
          DeclarationOrBridge(libraryIndex, bridge: constructor.value);
    }
    
    // 一个类可能有多个方法,放进去
    for (final method in bridge.methods.entries) {
      if (method.value.isStatic) {
        _topLevelDeclarationsMap[libraryIndex]![
                '${spec.name}.${method.key}'] =
            DeclarationOrBridge(libraryIndex, bridge: method.value);
      }
    }
  } else if (bridge is BridgeEnumDef) { // 枚举桥接
    final spec = bridge.type.spec!;
    _topLevelDeclarationsMap[libraryIndex]![spec.name] =
        DeclarationOrBridge(libraryIndex, bridge: bridge);
  } else if (bridge is BridgeFunctionDeclaration) { // 方法桥接
    _topLevelDeclarationsMap[libraryIndex]![bridge.name] =
        DeclarationOrBridge(libraryIndex, bridge: bridge);
  }
  return;
}

从中可以看出,哪一种桥接声明,就创建一个 DeclarationOrBridge,如果是桥接类,创建的声明更多一些。

类桥接处理

向顶层声明注册表中注册:

  1. 桥接类名称
  2. 构造方法(可能不止一个):桥接类名.构造方法名
  3. 方法(不止一个):桥接类名.方法名

注册内容都是:DeclarationOrBridge,是对 Dart Analyzer AST 不同粒度的拆分,这样就把 AST,从大的类粒度,拆得更细了。

// 如果是类桥接
if (bridge is BridgeClassDef) {
  final spec = bridge.type.type.spec!;
  
  // 类本身放进去
  // Map 第一个维度:library 对应的标识
  // Map 第二个维度:桥接类的名称
  _topLevelDeclarationsMap[libraryIndex]![spec.name] =
      DeclarationOrBridge(libraryIndex, bridge: bridge);
      
  // 对于类桥接,不仅要将类名注册到顶层声明,还要注册:
  // 1. 构造方法(可能不止一个):桥接类名.构造方法名
  // 2. 方法(不止一个):桥接类名.方法名
  
  // 一个类可能有多个构造方法,放进去
  for (final constructor in bridge.constructors.entries) {
    _topLevelDeclarationsMap[libraryIndex]![
            '${spec.name}.${constructor.key}'] =
        DeclarationOrBridge(libraryIndex, bridge: constructor.value);
  }
  
  // 一个类可能有多个方法,放进去
  for (final method in bridge.methods.entries) {
    if (method.value.isStatic) {
      _topLevelDeclarationsMap[libraryIndex]![
              '${spec.name}.${method.key}'] =
          DeclarationOrBridge(libraryIndex, bridge: method.value);
    }
  }
}

TopLevelVariableDeclaration 处理逻辑

顶层变量声明处理逻辑。注:TopLevelVariableDeclaration 参见《Dart Analyzer:TopLevelVariableDeclaration

变量声明可以一次声明多个变量,首先获取这些变量:

final vlist = declaration.variables;

这里初始化了 3 个结构,说明这些结构要用到:

if (!_topLevelGlobalIndices.containsKey(libraryIndex)) {
  _topLevelGlobalIndices[libraryIndex] = {};
  ctx.topLevelGlobalInitializers[libraryIndex] = {};
  ctx.topLevelVariableInferredTypes[libraryIndex] = {};
}

遍历这些变量进行处理:

for (final variable in vlist.variables) {
  // 变量名
  final name = variable.name2.value() as String;

  // 如果重复定义全局变量,会抛出异常
  if (_topLevelDeclarationsMap[libraryIndex]!.containsKey(name)) {
    throw CompileError('Cannot define "$name" twice in the same library',
        variable, libraryIndex);
  }

  // 向顶层声明注册表中注册该顶层变量
  _topLevelDeclarationsMap[libraryIndex]![name] =
      DeclarationOrBridge(libraryIndex, declaration: variable);
  // _topLevelGlobalIndices 是维护全局标识的,看起来顶层每个东西都有一个唯一标识
  // 自增
  _topLevelGlobalIndices[libraryIndex]![name] = ctx.globalIndex++;
}

NamedCompilationUnitMember 处理逻辑